
////////////////////////////////////////////////////////////////////////////
//	File Name: TSparseMatrix.inl		Last modification at : 2/13/2003 2:01:25 AM
//	Copyright 1999-2003 Microsoft Corporation. All Rights Reserved.
//
//	Author:      Rong Xiao
//	Email :      t-rxiao@microsoft.com
//
//	Description : 
//
//	Revision History: 
//
////////////////////////////////////////////////////////////////////////////

//********************************************************
//	Section 3: Memory Allocate
//********************************************************

template <typename T>
inline void* TSparseMatrix<T>::NewSize(int nRows, int nCols)
{
	initSize(nRows,nCols);

	if ( m_pRowVect )
		delete[] m_pRowVect;
	
	m_pRowVect = new TSparseVector<T>[nRows];

	for ( int i=0; i<nRows; i++)
		m_pRowVect[i].NewSize(nCols);
	
	return m_pRowVect;
}

// @cmember Release the memory if needed.
template <typename T>
inline void TSparseMatrix<T>::Destroy()
{
	initSize(0,0);

	if ( m_pRowVect )
		delete[] m_pRowVect;
}


	
//*************************************************
//	Section 6:  Access the TSparseMatrix Data
//*************************************************
	//*********************************************************
	//	Section 6.2:	Type Cast operation
	//*********************************************************

	// @cmember Type convertor between difference types

template <typename T>
inline TSparseMatrix<T>::operator TCharSparseMatrix() const
{
	TCharSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TCharSparseVector) m_pRowVect[i];
	}
	return retVal;
}


template <typename T>
inline TSparseMatrix<T>::operator TShortSparseMatrix() const
{
	TShortSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TShortSparseVector) m_pRowVect[i];
	}
	return retVal;
	
}

template <typename T>
inline TSparseMatrix<T>::operator TIntSparseMatrix() const
{
	TIntSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TIntSparseVector) m_pRowVect[i];
	}
	return retVal;
}

template <typename T>
inline TSparseMatrix<T>::operator TByteSparseMatrix() const
{
	TByteSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TByteSparseVector) m_pRowVect[i];
	}
	return retVal;
}

template <typename T>
inline TSparseMatrix<T>::operator TUShortSparseMatrix() const
{
	TUShortSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TUShortSparseVector) m_pRowVect[i];
	}
	return retVal;
}

template <typename T>
inline TSparseMatrix<T>::operator TUIntSparseMatrix() const
{
	TUIntSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TUIntSparseVector) m_pRowVect[i];
	}
	return retVal;
}

template <typename T>
inline TSparseMatrix<T>::operator TFloatSparseMatrix() const
{
	TFloatSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TFloatSparseVector) m_pRowVect[i];
	}
	return retVal;
}

template <typename T>
inline TSparseMatrix<T>::operator TDoubleSparseMatrix() const
{
	TDoubleSparseMatrix retVal(m_Rows,m_Cols);
	for ( int i=0; i<m_Rows; i++ ) {
		retVal[i] = (TDoubleSparseVector) m_pRowVect[i];
	}
	return retVal;
}

template <typename T>
inline TSparseMatrix<T>::operator TSparseVector<T>()  const
{
	TSparseVector<T> retVal(m_Size);
	int nLen,nIndex;
	T Value;
	for ( int i=0; i<m_Rows; i++) {
		nLen=m_pRowVect[i].GetLen();
		for ( int j=0; j<nLen; j++ ) {
			nIndex= m_pRowVect[i].GetSparseIndex(j);
			Value = m_pRowVect[i].GetSparseValue(j);
			retVal.push_back(i*m_Cols+nIndex,Value);
		}
	}
	return retVal;
}

	//**********************************************************
	//	Section 6.4 Input and Output 
	//**********************************************************

// It turned to global operator
template <typename T>
inline void TSparseMatrix<T>::ImportDiagonalMat(TVector<T>& vect)
{
	int nDim=vect.GetDim();
	InitSize(nDim,nDim);
	for ( int i=0; i<nDim; i++)
		m_pRowVect[i].push_back(i,vect[i]);
}


	// @cmember write down the SparseMatrix 

template <typename T>
inline int TSparseMatrix<T>::Write(const char* szFname, bool bBinary) const
{
	assert(szFname);
	std::ofstream Fout;
	
	if ( bBinary==true ) Fout.open(szFname, std::ios::binary);
	else Fout.open(szFname);
	
    return Write(Fout,bBinary);
}


template <typename T>
inline int TSparseMatrix<T>::Write(std::ostream& Fout, bool bBinary) const
{
	assert(Fout);
    if (!Fout) return -1;
	
	int i,nLen;
	if ( bBinary==true ) {
		if ( WriteTMatrixHeader( Fout, sizeof(T), m_Rows, m_Cols)==-1 ) {
			std::cout << "Input Header parameter invalid!" << std::endl;
			return -1;
		}
		for ( i=0; i<m_Rows; i++ ) {
			nLen=m_pRowVect[i].GetLen();
			Fout.write((const char*)&nLen, sizeof(int));
			if ( nLen >0 ) {
				Fout.write(m_pRowVect[i].GetSparseIndexPtr(),nLen*sizeof(int));
				Fout.write(m_pRowVect[i].GetSparseValuePtr(),nLen*sizeof(T));
			}
		}	
	}
	else {
		Fout << m_Rows << ' ' << m_Cols  << std::endl;	
		for ( i=0; i<m_Rows; i++ ) {
			nLen=m_pRowVect[i].GetLen();
			Fout << nLen;
			for ( int j=0; j<nLen; j++) {
				Fout << ' ' << m_pRowVect[i].GetSparseIndex(j) << ':';
				IOTraits<T>::Write(Fout, m_pRowVect[i].GetSparseValue(j));
			}
			Fout << std::endl;
		}
	}
	return 0;
}


    // @cmember read the SparseMatrix 

template <typename T>
inline int TSparseMatrix<T>::Read(const char* szFname, bool bBinary)
{
    assert(szFname);
	std::ifstream Fin;
	if (bBinary==true)
		Fin.open(szFname,std::ios::binary );
	else
		Fin.open(szFname);
	
    return Read(Fin, bBinary);  	
}

template <typename T>
inline int TSparseMatrix<T>::Read(std::istream& Fin, bool bBinary)
{
    assert(Fin);
    if (!Fin) return -1;
	
    int i, iRows, iCols;
	int nLen, nTSize;
	
	if ( true==bBinary ) {
		if ( ReadTMatrixHeader( Fin, nTSize, iRows, iCols) == -1 ) {
			std::cout << "Matrix Data Header has been destroyed!" << std::endl;    
			return -1;
		}
		
		if ( nTSize != sizeof(T) ) {
			std::cout << "Data type mismatch!" << std::endl;
			return -1;
		}
		NewSize(iRows,iCols);
		for ( i=0; i<m_Rows; i++ ) {
			Fin.read((char*)&nLen,sizeof(int));
			if ( nLen>0 ) {
				m_pRowVect[i].ResizeSparseBuffer(nLen);
				Fin.read(m_pRowVect[i].GetSparseIndexPtr(),nLen*sizeof(int));
				Fin.read(m_pRowVect[i].GetSparseValuePtr(),nLen*sizeof(T));
			}
		}
	}
	else {
		T Value;
		char cSep;
		int index;
		
		Fin >> iRows >> iCols;
		NewSize(iRows, iCols);
		for ( i=0; i<m_Rows; i++ ) {
			Fin >> nLen;
			if ( nLen>0 ) {
				m_pRowVect[i].ReserveSparseBuffer(nLen);
				
				for ( int j=0; j<nLen; j++ ) {
					Fin >> index >>cSep ;
					IOTraits<T>::Read(Fin, Value);
					m_pRowVect[i].push_back(index,Value);
				}
			}
		}
	}
	return 0;
}


	//************************************************
	//	Section 6.5:	Is?
	//************************************************
	// @cmember Is this index valid?

template <typename T>
inline bool TSparseMatrix<T>::IsIndexValid(int row, int col) const
{
	if ( row<0 || col<0 || row>=m_Rows || col >=m_Cols ) 
		return false; 
	else 
		return true; 	
}


//**********************************************************
//		Section 7: Algorithms
//**********************************************************

	//**********************************************************
	//	Section 7.1:	Min and Max Operation 
	//**********************************************************
template <typename T>
inline TVector<T> TSparseMatrix<T>::RowMin() const
{
	TVector<T> retVal(m_Rows);
	
	for ( int i=0; i<m_Rows; i++)
		retVal[i]=m_pRowVect[i].Min();

	return retVal;
}

template <typename T>
inline TVector<T> TSparseMatrix<T>::RowMax() const
{
	TVector<T> retVal(m_Rows);
	
	for ( int i=0; i<m_Rows; i++)
		retVal[i]=m_pRowVect[i].Max();
	
	return retVal;
	
}


template <typename T>	
inline T TSparseMatrix<T>::Min() const
{
	TVector<T> retVal(m_Rows);
	
	for ( int i=0; i<m_Rows; i++)
		retVal[i]=m_pRowVect[i].Min();
	
	return retVal.Min();
}

template <typename T>
inline T TSparseMatrix<T>::Max() const
{
	TVector<T> retVal(m_Rows);
	
	for ( int i=0; i<m_Rows; i++)
		retVal[i]=m_pRowVect[i].Max();
	
	return retVal.Max();
}



	//************************************************
	//	Section 7.2: SparseMatrix Computation 
	//************************************************
// @cmember Return the transposed SparseMatrix.
template <typename T>
inline TSparseMatrix<T> TSparseMatrix<T>::Transpose() const
{
	TSparseMatrix<T> retVal(m_Cols, m_Rows);
	int nLen,nIndex;
	T Value;
	for ( int i=0; i<m_Rows; i++) {
		nLen=m_pRowVect[i].GetLen();
		for ( int j=0; j<nLen; j++ ) {
			nIndex= m_pRowVect[i].GetSparseIndex(j);
			Value = m_pRowVect[i].GetSparseValue(j);
			retVal.m_pRowVect[nIndex].push_back(i,Value);
		}
	}
	return retVal;
}


// @cmember Transpose this object.
template <typename T>
inline void TSparseMatrix<T>::SelfTranspose()
{
	*this = Transpose();
}




// @cmember return sum of all elements
template <typename T>
inline T TSparseMatrix<T>::TSum(void) const
{
	T sum=0;
	for ( int i=0; i<m_Rows; i++)
		sum += m_pRowVect[i].TSum();

	return sum;
}

template <typename T>
inline double TSparseMatrix<T>::Sum(void) const
{
	double sum=0;
	for ( int i=0; i<m_Rows; i++)
		sum += m_pRowVect[i].TSum();

	return sum;
}


// @cmember return mean of rows
template <typename T>
inline TMatrix<T> TSparseMatrix<T>::MeanCol(void) const
{
	TMatrix<T> retVal(m_Rows,1);
	for ( int i=0; i<m_Rows; i++) 
		retVal(i,0)=m_pRowVect[i].Mean();
	return retVal;
}



//***************************************************
//	Section 8:	OverRide Operation 
//***************************************************
	// @cmember Operator [], used to access the element of SparseMatrix
//		This is const version, It is necessary.
template <typename T>
inline const TSparseVector<T>& TSparseMatrix<T>::operator[](int rows) const
{
	assert ( rows>=0 && rows<m_Rows && m_pRowVect);
	return m_pRowVect[rows];
}

	
// @cmember Operator [], used to access the element of SparseMatrix
template <typename T>
inline TSparseVector<T>& TSparseMatrix<T>::operator[](int rows)
{
	assert ( rows>=0 && rows<m_Rows && m_pRowVect);
	return m_pRowVect[rows];
}


// @cmember Operator =: Copy from another SparseMatrix
template <typename T>
inline TSparseMatrix<T>& TSparseMatrix<T>::operator=(const TSparseMatrix<T>& ref)
{
	NewSize(ref.GetRows(), ref.GetCols());
	for ( int i=0; i<m_Rows; i++)
		m_pRowVect[i]=ref[i];
	return *this;
}



// @cmember SparseMatrix multiple
template <typename T>
inline TMatrix<T> TSparseMatrix<T>::operator*(const TSparseMatrix<T>& ref) const
{
	int newRow, newCol;

	assert ( m_Cols==ref.GetRows());
	
	newRow=m_Rows;
	newCol=ref.GetCols();

	TMatrix<T> retVal(newRow, newCol);
	TSparseMatrix<T> tmp;

	tmp=ref.Transpose();
	for ( int i=0; i<newRow; i++) 
		for ( int j=0; j<newCol; j++)
			retVal(i,j)=m_pRowVect[i]*tmp[j];

	return retVal;
}

template <typename T>
inline TMatrix<T> TSparseMatrix<T>::operator*(const TMatrix<T>& ref) const
{
	int newRow, newCol;

	assert ( m_Cols==ref.GetRows());
	
	newRow=m_Rows;
	newCol=ref.GetCols();

	TMatrix<T> retVal(newRow, newCol);

	T sum;
	for ( int i=0; i<newRow; i++) 
		for ( int j=0; j<newCol; j++) {
			int nLen=m_pRowVect[i].GetLen();
			if ( nLen==0 )
				retVal(i,j)=0;
			else {
				sum=0;
				for ( int k=0; k<nLen; k++) 
					sum+=m_pRowVect[i].GetSparseValue(k)*ref(m_pRowVect[i].GetSparseIndex(k),j);
				retVal(i,j)=sum;
			}
		}

	return retVal;
}

// @cmember SparseMatrix multiple
template <typename T>
inline TVector<T> TSparseMatrix<T>::operator*(const TSparseVector<T>& ref) const
{
	TVector<T> retVal(m_Rows);
	assert ( m_Cols==ref.GetDim() );
	for ( int i=0; i<m_Rows; i++)
		retVal[i]=m_pRowVect[i]*ref;
	return retVal;
}

template <typename T>
inline TVector<T> TSparseMatrix<T>::operator*(const TVector<T>& ref) const
{
	TVector<T> retVal(m_Rows);
	assert ( m_Cols==ref.GetDim() );
	for ( int i=0; i<m_Rows; i++)
		retVal[i]=m_pRowVect[i]*ref;
	return retVal;
}

// @cmember multiple a numeric
template <typename T>
inline TSparseMatrix<T> TSparseMatrix<T>::operator*(const T scale) const
{
	TSparseMatrix<T> retVal(m_Rows, m_Cols);

	for ( int i=0; i<m_Rows;i++)
		retVal[i]=m_pRowVect[i]*scale;
	return retVal;
}


// @cmember all the elements divide a numeric
template <typename T>
inline TSparseMatrix<T> TSparseMatrix<T>::operator/(const T scale) const
{
	TSparseMatrix<T> retVal(m_Rows, m_Cols);

	for ( int i=0; i<m_Rows;i++)
		retVal[i]=m_pRowVect[i]/scale;
	return retVal;
	
}



// @cmember multiple a numeric to all the element
template <typename T>
void TSparseMatrix<T>::operator*=(const T scale)
{
	for ( int i=0; i<m_Rows;i++)
		m_pRowVect[i]*=scale;
}


// @cmember each elements divide a numeric
template <typename T>
void TSparseMatrix<T>::operator/=(const T scale)
{
	for ( int i=0; i<m_Rows;i++)
		m_pRowVect[i]/=scale;
}


//***************************************************
//	Section 9:	Friend Functions
//***************************************************

template <typename T>
inline std::ostream& operator << (std::ostream& os, const TSparseMatrix<T>& mat)
{
	mat.Write(os,false);	
	return os;	
}

template <typename T>
inline std::istream& operator >> (std::istream& is, TSparseMatrix<T>& mat)
{
	mat.Read(is,false);
	return is;
}


